#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <iostream>
#include <cmath>

#include "Shader.h"

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// 窗口大小变化回调函数
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
    glViewport(0, 0, width, height);
}

// 输入处理
void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

// 打印使用说明
void printUsage(const char* programName) {
    std::cout << "Usage: " << programName << " [vertex_shader] [fragment_shader]" << std::endl;
    std::cout << "Example: " << programName << " ../data/shader.vs ../data/shader.fs" << std::endl;
    std::cout << "If no shaders are specified, default shaders will be used." << std::endl;
}

int main(int argc, char* argv[])
{
    // 检查命令行参数
    std::string vertexShaderPath = "../data/shader.vs";
    std::string fragmentShaderPath = "../data/shader.fs";
    
    if (argc == 2 && (std::string(argv[1]) == "--help" || std::string(argv[1]) == "-h")) {
        printUsage(argv[0]);
        return 0;
    }
    
    if (argc >= 3) {
        vertexShaderPath = argv[1];
        fragmentShaderPath = argv[2];
    } else if (argc > 1) {
        std::cout << "Insufficient arguments provided." << std::endl;
        printUsage(argv[0]);
        return -1;
    }
    
    std::cout << "Using vertex shader: " << vertexShaderPath << std::endl;
    std::cout << "Using fragment shader: " << fragmentShaderPath << std::endl;

    /**
     * 实例化GLFW窗口
     */
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    /**
     * 创建窗口对象
     */
    GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", nullptr, nullptr);
    if (window == nullptr)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    // 设置OpenGL上下文
    glfwMakeContextCurrent(window);

    /**
     * 初始化GLAD
     */
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 使用着色器文件创建着色器程序
    Shader ourShader(vertexShaderPath.c_str(), fragmentShaderPath.c_str());

    // 创建顶点数组对象
    unsigned int VAO;
    glGenVertexArrays(1, &VAO); // 创建顶点数组对象
    glBindVertexArray(VAO);     // 绑定顶点数组对象

    // 创建顶点缓冲对象
    unsigned int VBO;
    glGenBuffers(1, &VBO);

    // 绑定顶点缓冲对象
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    /**
     * 顶点输入
     *
     */
    float vertices[] = {
        // 位置             // 颜色
        0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,   // 右下
        -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,  // 左下
        0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f     // 顶部
    };

    // 把顶点数据复制到缓冲的内存中
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);                   // 位置属性
    glEnableVertexAttribArray(0);                                                                    // 启用位置属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float))); // 颜色属性
    glEnableVertexAttribArray(1);                                                                    // 启用颜色属性

    // 注册窗口大小变化回调函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    /**
     * 渲染循环
     */
    while (!glfwWindowShouldClose(window))
    {
        processInput(window); // 处理输入

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 设置清除颜色
        glClear(GL_COLOR_BUFFER_BIT);         // 清除颜色缓冲

        // 使用着色器程序
        ourShader.use();

        // 更新uniform颜色值
        float timeValue = glfwGetTime();
        float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
        ourShader.setFloat("ourColor", greenValue);

        glm::vec4 offset(0.5f, 0.0f, 0.0f, 0.0f);
        ourShader.setVec4("offset", offset);

        glBindVertexArray(VAO);           // 绑定顶点数组对象
        glDrawArrays(GL_TRIANGLES, 0, 3); // 绘制三角形

        glfwSwapBuffers(window); // 交换缓冲
        glfwPollEvents();        // 轮询事件
    }

    // 删除缓冲对象和顶点数组对象
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);

    // 释放资源
    glfwTerminate();

    return 0;
}